﻿// A Force-Directed Diagram Layout Algorithm
// Bradley Smith - 2010/07/01

using System;

/// <summary>
/// Represents a vector whose magnitude and direction are both expressed as System.Double. 
/// Vector addition and scalar multiplication are supported.
/// </summary>
namespace FriendAnalyzer.Graph
{
    public struct Vector
    {

        private double mMagnitude;
        private double mDirection;

        /// <summary>
        /// Gets or sets the magnitude of the vector.
        /// </summary>
        public double Magnitude
        {
            get { return mMagnitude; }
            set { mMagnitude = value; }
        }
        /// <summary>
        /// Gets or sets the direction of the vector.
        /// </summary>
        public double Direction
        {
            get { return mDirection; }
            set { mDirection = value; }
        }

        /// <summary>
        /// Initialises a new instance of the Vector class using the specified magnitude and direction. 
        /// Automatically simplifies the representation to ensure a positive magnitude and a sub-circular angle.
        /// </summary>
        /// <param name="magnitude">The magnitude of the vector.</param>
        /// <param name="direction">The direction of the vector, in degrees.</param>
        public Vector(double magnitude, double direction)
        {
            mMagnitude = magnitude;
            mDirection = direction;

            if (mMagnitude < 0)
            {
                // resolve negative magnitude by reversing direction
                mMagnitude = -mMagnitude;
                mDirection = (180.0 + mDirection) % 360;
            }

            // resolve negative direction
            if (mDirection < 0) mDirection = (360.0 + mDirection);
        }

        /// <summary>
        /// Calculates the resultant sum of two vectors.
        /// </summary>
        /// <param name="a">The first operand.</param>
        /// <param name="b">The second operand.</param>
        /// <returns>The result of vector addition.</returns>
        public static Vector operator +(Vector a, Vector b)
        {
            // break into x-y components
            double aX = a.Magnitude * Math.Cos((Math.PI / 180.0) * a.Direction);
            double aY = a.Magnitude * Math.Sin((Math.PI / 180.0) * a.Direction);

            double bX = b.Magnitude * Math.Cos((Math.PI / 180.0) * b.Direction);
            double bY = b.Magnitude * Math.Sin((Math.PI / 180.0) * b.Direction);

            // add x-y components
            aX += bX;
            aY += bY;

            // pythagorus' theorem to get resultant magnitude
            double magnitude = Math.Sqrt(Math.Pow(aX, 2) + Math.Pow(aY, 2));

            // calculate direction using inverse tangent
            double direction;
            if (magnitude == 0.0)
                direction = 0.0;
            else if (Math.Abs(aX) > Math.Abs(aY))
                direction = ((180.0 / Math.PI) * Math.Tanh(aY / aX));
            else
                direction = 90.0 - ((180.0 / Math.PI) * Math.Tanh(aX / aY));

            // apply correction depending on quadrant
            if ((aX < 0) && ((aY < 0) || (direction < 0)))
                direction += 180.0;
            else if ((aY < 0) && (direction >= 0))
                direction += 180.0;

            return new Vector(magnitude, direction);
        }

        /// <summary>
        /// Calculates the result of multiplication by a scalar value.
        /// </summary>
        /// <param name="vector">The Vector that forms the first operand.</param>
        /// <param name="multiplier">The System.Double that forms the second operand.</param>
        /// <returns>A Vector whose magnitude has been multiplied by the scalar value.</returns>
        public static Vector operator *(Vector vector, double multiplier)
        {
            // only magnitude is affected by scalar multiplication
            return new Vector(vector.Magnitude * multiplier, vector.Direction);
        }

        /// <summary>
        /// Converts the vector into an X-Y coordinate representation.
        /// </summary>
        /// <returns>An X-Y coordinate representation of the Vector.</returns>
        public Point ToPoint()
        {
            // break into x-y components
            double aX = mMagnitude * Math.Cos((Math.PI / 180.0) * mDirection);
            double aY = mMagnitude * Math.Sin((Math.PI / 180.0) * mDirection);
            //erau castate la ints
            return new Point(aX, aY);
        }

        /// <summary>
        /// Returns a string representation of the vector.
        /// </summary>
        /// <returns>A System.String representing the vector.</returns>
        public override string ToString()
        {
            return mMagnitude.ToString("N5") + " " + mDirection.ToString("N2") + "°";
        }
    }
}